﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZGSharp;
using ZGSharp.DataSets;
using ZGSharp.Layers;

namespace ZGSharpTest
{
    internal class TestAllUnits
    {
        public static int Test() 
        {
            //TestDropOut
            if (false) {
                Console.WriteLine("Test Dropout");
                double[] testArray = new double[20];
                for (int i = 0; i < testArray.Length; i++) 
                {
                    testArray[i] = i / 10.0;
                }
                Tensor testTensor = Tensor.ToTensor(new int[] { 2, 10 }, testArray);
                Console.WriteLine("testTensor");
                testTensor.PrintValue();
                Tensor dropout = ZGSharp.Layers.Dropout.dropout(testTensor);
                Console.WriteLine("dropout");
                dropout.PrintValue();
                Array.Copy(testArray, dropout.outputs, 20);
                dropout.Backward(null, 1);
                Console.WriteLine("Gradient");
                testTensor.PrintGradient();
            }

            //test readuce mean
            if (false)
            {
                Console.WriteLine("Reduce.mean");
                double[] array = new double[3 * 4 * 5 * 6];
                for (int i = 0; i < 3 * 4 * 5 * 6; i++)
                {
                    array[i] = i;
                }
                Tensor tensor = Tensor.ToTensor(new int[] { 3, 4, 5, 6 }, array);
                Console.WriteLine("test tensor");
                tensor.PrintValue();
                Tensor reduce1 = Reduce.mean(tensor, new int[] { 2, 3 });
                Console.WriteLine("mean 2,3");
                reduce1.PrintValue();
                Tensor reduce = Reduce.mean(reduce1);
                Console.WriteLine("mean all");
                reduce.PrintValue();
                reduce.Backward(null, 1);
                Console.WriteLine("Gradient tensor");
                tensor.PrintGradient();
            }

            //test linear
            if (false)//(2, 4) (4, 3) (2, 3)
            {
                double[] array = new double[2 * 4];
                for (int i = 0; i < 2 * 4; i++)
                {
                    array[i] = i;
                }
                Tensor tensor = Tensor.ToTensor(new int[] { 2, 4 }, array);
                Console.WriteLine("test tensor");
                tensor.PrintValue(3); //[[0,1,2,3],[4,5,6,7]]
                Linear linear = new Linear(4, 3);//[[0, 0.1, 0.2],[0.3, 0.4, 0.5],[0.6, 0.7, 0.8],[0.9, 1, 1.1]]
                for (int i = 0; i < 4 * 3; i++) 
                {
                    linear.weights[i] = i / 10.0;
                }
                for (int i = 0; i < 3; i++)//[0, 1, 2]
                {
                    linear.bias[i] = i;
                }
                Console.WriteLine("linear init weigts");
                linear.PrintWeights(3);
                linear.LayerPred(tensor);
                Console.WriteLine("test linear");
                linear.PrintValue(3); //[[ 4.2,  5.8,  7.4], [11.4, 14.6, 17.8]]
                for (int i = 0; i < 6; i++)//[[0, 1, 2], [3 ,4 ,5]] 
                {
                    linear.outputs[i] = i;
                }
                linear.Backward(null, 1);
                Console.WriteLine("Gradient tensor");
                tensor.PrintGradient(3);//[[ 0.5,  1.4,  2.3,  3.2], [ 1.4,  5. ,  8.6, 12.2]
                Console.WriteLine("liner weigts");
                linear.PrintWeights(3);// -[[12, 16, 20], [15, 21, 27], [18, 26, 34], [21, 31, 41]] / 2 + [[0, 0.1, 0.2],[0.3, 0.4, 0.5],[0.6, 0.7, 0.8],[0.9, 1, 1.1]]
                //bias[0, 1, 2] - ([0, 1, 2] + [3 ,4 ,5]) / 2
                Console.WriteLine("end");
            }

            //test softmax
            if (false)
            {
                Console.WriteLine("test softmax");
                double[] array = new double[2 * 4];
                for (int i = 0; i < 2 * 4; i++)
                {
                    array[i] = i;
                }
                Tensor tensor = Tensor.ToTensor(new int[] { 2, 4 }, array);
                Console.WriteLine("test tensor");
                tensor.PrintValue(3); //[[0,1,2,3],[4,5,6,7]]
                Tensor softmax = Softmax.softmax(tensor);
                softmax.PrintValue(3); //[[0.0320586 , 0.08714432, 0.23688282, 0.64391426], [0.0320586 , 0.08714432, 0.23688282, 0.64391426]]
                softmax.BackwordInit(softmax);
                for (int i = 0; i < 2 * 4; i++)
                {
                    softmax.gradient[i] = i / 10.0;
                }
                softmax.Backward(null, 1);//[3.46944695e-18, 6.93889390e-18, 0.00000000e+00, 2.77555756e-17] * [[0, 0.1, 0.2, 0.3], [0.4, 0.5, 0.6, 0.7]]
                Console.WriteLine("Gradient tensor");
                tensor.PrintGradient(3);
                Console.WriteLine("test softmax end");
            }

            //测试mnist
            if (false) 
            {
                Mnist mnist = new Mnist();
                mnist.InitMinst(@"C:\Users\lizhigong\SVNS\当前项目\ZGSharp\DataSets\Mnist");
                double[] input_data = new double[2 * 28 * 28];
                int[] label_data = new int[2];
                mnist.GetBatchTrainData(2, input_data, label_data);
                Tensor data = Tensor.ToTensor(new int[] { 2, 28, 28 }, input_data);
                Console.WriteLine("train data");
                data.PrintValue(0);
                Tensor label_t = CommonDef.GetOneHot(label_data, 10);
                Console.WriteLine("train label");
                label_t.PrintValue();

                mnist.GetBatchTestData(2, input_data, label_data);
                data = Tensor.ToTensor(new int[] { 2, 28, 28 }, input_data);
                Console.WriteLine("test data");
                data.PrintValue(0);
                label_t = CommonDef.GetOneHot(label_data, 10);
                Console.WriteLine("test label");
                label_t.PrintValue();
            }

            //test conv2d
            if (true)
            {
                Console.WriteLine("test conv2d");
                double[] array = new double[1 * 3 * 3 * 1];
                for (int i = 0; i < 1 * 3 * 3 * 1; i++)
                {
                    array[i] = i;
                }
                Tensor tensor = Tensor.ToTensor(new int[] { 1, 3, 3, 1 }, array);
                Console.WriteLine("test tensor");
                tensor.PrintValue(3);
                Conv2D conv = new Conv2D(1, 2, new int[] {2, 2 });//height, width, inc, outc 
                for (int i = 0; i < 1 * 2 * 2 * 2; i++) 
                {
                    conv.weights[i] = i / 10.0;
                }
                conv.LayerPred(tensor); //(1, 2, 2, 2) [[1.9, 5.1], [2.5, 7.3]], [[3.7, 11.7], [4.3, 13.9]]
                conv.PrintValue(3);
                conv.BackwordInit(conv);
                for (int i = 0; i < 2 * 4; i++)
                {
                    conv.outputs[i] = 1;
                }
                for (int i = 0; i < 1 * 2 * 2 * 2; i++)
                {
                    conv.weights[i] = 1;
                }
                for (int i = 0; i < 2 * 4; i++)
                {
                    conv.gradient[i] = 1;
                }
                conv.Backward(null, 1);
                Console.WriteLine("Gradient tensor");
                tensor.PrintGradient(3);
                Console.WriteLine("test conv2d end");
            }

            return 0;
        }
    }
}
